package tcp

import (
	"log"
	"net"
	"sync"
	"sync/atomic"
	"tym/modbus"
)

type Client struct {
	tsId    uint32
	Address string

	mux  sync.Mutex
	conn net.Conn
}

func NewClient(address string) *Client {

	dialer := net.Dialer{}
	dial, err := dialer.Dial("tcp", address)
	if err != nil {
		panic(err)
	}
	client := &Client{
		Address: address,
		conn:    dial,
	}
	return client
}

func (c *Client) ReadHoldingRegisters(slaveId, address, numRegisters uint16) []uint16 {

	c.mux.Lock()
	defer c.mux.Unlock()

	tsId := atomic.AddUint32(&c.tsId, 1)
	packer := Pack(uint16(tsId), uint8(slaveId), modbus.FuncCodeReadHoldingRegisters, address, numRegisters)

	resp, err := c.Send(packer)
	if err != nil {
		log.Printf("modbus client error: %v", err)
		return nil
	}
	log.Printf("revc data: %v \n", resp)

	return resp
}

func (c *Client) Send(packager modbus.Packager) ([]uint16, error) {
	pack := packager.Encode()

	_, err := c.conn.Write(pack)
	if err != nil {
		return nil, err
	}

	buf := make([]byte, 512)
	lens, err := c.conn.Read(buf)
	if err != nil {
		return nil, err
	}

	aduResponse := buf[:lens]

	return packager.Decode(aduResponse), nil
}

func (c *Client) WriteHoldingRegisters(slaveId, address, value uint16) []uint16 {
	c.mux.Lock()
	defer c.mux.Unlock()

	tsId := atomic.AddUint32(&c.tsId, 1)
	packer := Pack(uint16(tsId), uint8(slaveId), modbus.FuncCodeWriteHoldingRegisters, address, value)

	resp, err := c.Send(packer)
	if err != nil {
		log.Printf("modbus client error: %v", err)
		return nil
	}
	log.Printf("revc data: %v \n", resp)

	return resp
}

func (c *Client) Close() error {
	return c.conn.Close()
}
